#!/usr/bin/env python3
"""
Redis Key 管理工具
提供 Redis key 的查看、分析、清理等功能

使用方法:
python scripts/redis_key_manager.py <command> [options]

命令:
list        - 列出所有系统 key
analyze     - 分析 key 的分布和使用情况
clean       - 清理过期或无效的 key
export      - 导出 key 列表
validate    - 验证 key 的命名规范

示例:
python scripts/redis_key_manager.py list --category monitor
python scripts/redis_key_manager.py analyze --verbose
python scripts/redis_key_manager.py clean --dry-run
"""

import asyncio
import argparse
import json
import sys
import os
from typing import List, Dict, Optional, Set
from datetime import datetime
from collections import defaultdict

# 添加项目根目录到 Python 路径
script_dir = os.path.dirname(os.path.abspath(__file__))
project_root = os.path.dirname(script_dir)
backend_dir = os.path.join(project_root, 'backend')
sys.path.insert(0, backend_dir)

from app.core.redis_client import redis_manager
from app.core.redis_keys import RedisKeys
from app.utils.logger import get_logger

logger = get_logger(__name__)

class RedisKeyManager:
    """Redis Key 管理器"""
    
    def __init__(self, verbose: bool = False):
        self.verbose = verbose
    
    async def list_keys(self, category: Optional[str] = None, pattern: Optional[str] = None) -> List[str]:
        """列出系统 key"""
        client = await redis_manager.get_client()
        
        if pattern:
            search_pattern = pattern
        elif category:
            search_pattern = RedisKeys.get_pattern(category)
        else:
            search_pattern = f"{RedisKeys.get_system_prefix()}:*"
        
        keys = await client.keys(search_pattern)
        return [key.decode('utf-8') if isinstance(key, bytes) else key for key in keys]
    
    async def analyze_keys(self) -> Dict:
        """分析 key 的分布和使用情况"""
        print("🔍 分析 Redis key 分布...")
        
        all_keys = await self.list_keys()
        
        analysis = {
            'total_keys': len(all_keys),
            'system_keys': 0,
            'non_system_keys': 0,
            'categories': defaultdict(int),
            'subcategories': defaultdict(int),
            'key_sizes': {},
            'ttl_info': {},
            'invalid_keys': []
        }
        
        client = await redis_manager.get_client()
        
        for key in all_keys:
            # 检查是否为系统 key
            if RedisKeys.is_system_key(key):
                analysis['system_keys'] += 1
                
                # 解析 key 结构
                parsed = RedisKeys.parse_key(key)
                if parsed['valid']:
                    analysis['categories'][parsed['category']] += 1
                    if parsed['subcategory']:
                        subcategory_key = f"{parsed['category']}:{parsed['subcategory']}"
                        analysis['subcategories'][subcategory_key] += 1
                else:
                    analysis['invalid_keys'].append(key)
            else:
                analysis['non_system_keys'] += 1
            
            # 获取 key 大小
            try:
                memory_usage = await client.memory_usage(key)
                if memory_usage:
                    analysis['key_sizes'][key] = memory_usage
            except:
                pass
            
            # 获取 TTL 信息
            try:
                ttl = await client.ttl(key)
                if ttl >= 0:
                    analysis['ttl_info'][key] = ttl
                elif ttl == -1:
                    analysis['ttl_info'][key] = 'no_expire'
            except:
                pass
        
        return analysis
    
    async def clean_keys(self, dry_run: bool = True, categories: Optional[List[str]] = None) -> Dict:
        """清理过期或无效的 key"""
        print(f"🧹 清理 Redis key {'(DRY RUN)' if dry_run else ''}")
        
        client = await redis_manager.get_client()
        results = {
            'scanned': 0,
            'cleaned': 0,
            'errors': 0,
            'cleaned_keys': []
        }
        
        # 获取要清理的 key
        if categories:
            keys_to_check = []
            for category in categories:
                pattern = RedisKeys.get_pattern(category)
                category_keys = await client.keys(pattern)
                keys_to_check.extend([key.decode('utf-8') if isinstance(key, bytes) else key for key in category_keys])
        else:
            keys_to_check = await self.list_keys()
        
        results['scanned'] = len(keys_to_check)
        
        for key in keys_to_check:
            try:
                # 检查 key 是否存在
                if not await client.exists(key):
                    continue
                
                # 检查 TTL
                ttl = await client.ttl(key)
                should_clean = False
                reason = ""
                
                # 清理逻辑
                if ttl == 0:  # 已过期但未被清理
                    should_clean = True
                    reason = "已过期"
                elif not RedisKeys.is_system_key(key):
                    # 非系统 key，可能是旧格式
                    should_clean = True
                    reason = "非系统格式"
                
                if should_clean:
                    if self.verbose:
                        print(f"  清理 key: {key} (原因: {reason})")
                    
                    if not dry_run:
                        await client.delete(key)
                    
                    results['cleaned'] += 1
                    results['cleaned_keys'].append({'key': key, 'reason': reason})
                    
            except Exception as e:
                results['errors'] += 1
                if self.verbose:
                    print(f"  处理 key 时出错 {key}: {e}")
        
        return results
    
    async def export_keys(self, output_file: str, format: str = 'json') -> bool:
        """导出 key 列表"""
        print(f"📤 导出 key 列表到 {output_file}")
        
        try:
            all_keys = await self.list_keys()
            analysis = await self.analyze_keys()
            
            export_data = {
                'export_time': datetime.now().isoformat(),
                'total_keys': len(all_keys),
                'keys': all_keys,
                'analysis': dict(analysis)
            }
            
            # 转换 defaultdict 为普通 dict
            export_data['analysis']['categories'] = dict(export_data['analysis']['categories'])
            export_data['analysis']['subcategories'] = dict(export_data['analysis']['subcategories'])
            
            with open(output_file, 'w', encoding='utf-8') as f:
                if format == 'json':
                    json.dump(export_data, f, indent=2, ensure_ascii=False)
                elif format == 'txt':
                    f.write(f"Redis Key 导出报告\n")
                    f.write(f"导出时间: {export_data['export_time']}\n")
                    f.write(f"总 key 数量: {export_data['total_keys']}\n\n")
                    f.write("Key 列表:\n")
                    for key in all_keys:
                        f.write(f"  {key}\n")
            
            print(f"✅ 成功导出 {len(all_keys)} 个 key 到 {output_file}")
            return True
            
        except Exception as e:
            print(f"❌ 导出失败: {e}")
            return False
    
    async def validate_keys(self) -> Dict:
        """验证 key 的命名规范"""
        print("✅ 验证 key 命名规范...")
        
        all_keys = await self.list_keys()
        validation_results = {
            'total_keys': len(all_keys),
            'valid_keys': 0,
            'invalid_keys': 0,
            'issues': []
        }
        
        for key in all_keys:
            parsed = RedisKeys.parse_key(key)
            
            if parsed['valid']:
                validation_results['valid_keys'] += 1
            else:
                validation_results['invalid_keys'] += 1
                validation_results['issues'].append({
                    'key': key,
                    'reason': parsed.get('reason', '未知错误')
                })
        
        return validation_results
    
    def print_analysis_report(self, analysis: Dict):
        """打印分析报告"""
        print("\n📊 Redis Key 分析报告")
        print("=" * 50)
        
        print(f"总 key 数量: {analysis['total_keys']}")
        print(f"系统 key: {analysis['system_keys']}")
        print(f"非系统 key: {analysis['non_system_keys']}")
        
        if analysis['categories']:
            print("\n📂 分类分布:")
            for category, count in sorted(analysis['categories'].items()):
                print(f"  {category}: {count}")
        
        if analysis['subcategories']:
            print("\n📁 子分类分布:")
            for subcategory, count in sorted(analysis['subcategories'].items()):
                print(f"  {subcategory}: {count}")
        
        if analysis['invalid_keys']:
            print(f"\n⚠️  无效 key ({len(analysis['invalid_keys'])}):")
            for key in analysis['invalid_keys'][:10]:
                print(f"  {key}")
            if len(analysis['invalid_keys']) > 10:
                print(f"  ... 还有 {len(analysis['invalid_keys']) - 10} 个")
        
        # 内存使用统计
        if analysis['key_sizes']:
            total_memory = sum(analysis['key_sizes'].values())
            avg_memory = total_memory / len(analysis['key_sizes'])
            print(f"\n💾 内存使用:")
            print(f"  总内存: {total_memory:,} bytes")
            print(f"  平均大小: {avg_memory:.1f} bytes")
            
            # 显示最大的几个 key
            largest_keys = sorted(analysis['key_sizes'].items(), key=lambda x: x[1], reverse=True)[:5]
            print("  最大的 key:")
            for key, size in largest_keys:
                print(f"    {key}: {size:,} bytes")
        
        # TTL 统计
        if analysis['ttl_info']:
            no_expire_count = sum(1 for ttl in analysis['ttl_info'].values() if ttl == 'no_expire')
            with_ttl_count = len(analysis['ttl_info']) - no_expire_count
            print(f"\n⏰ TTL 信息:")
            print(f"  无过期时间: {no_expire_count}")
            print(f"  有过期时间: {with_ttl_count}")


async def main():
    """主函数"""
    parser = argparse.ArgumentParser(description='Redis Key 管理工具')
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # list 命令
    list_parser = subparsers.add_parser('list', help='列出系统 key')
    list_parser.add_argument('--category', help='按分类过滤')
    list_parser.add_argument('--pattern', help='按模式过滤')
    list_parser.add_argument('--verbose', '-v', action='store_true', help='显示详细信息')
    
    # analyze 命令
    analyze_parser = subparsers.add_parser('analyze', help='分析 key 分布')
    analyze_parser.add_argument('--verbose', '-v', action='store_true', help='显示详细信息')
    
    # clean 命令
    clean_parser = subparsers.add_parser('clean', help='清理无效 key')
    clean_parser.add_argument('--dry-run', action='store_true', help='只显示将要清理的 key')
    clean_parser.add_argument('--categories', nargs='+', help='指定要清理的分类')
    clean_parser.add_argument('--verbose', '-v', action='store_true', help='显示详细信息')
    
    # export 命令
    export_parser = subparsers.add_parser('export', help='导出 key 列表')
    export_parser.add_argument('output', help='输出文件路径')
    export_parser.add_argument('--format', choices=['json', 'txt'], default='json', help='输出格式')
    
    # validate 命令
    validate_parser = subparsers.add_parser('validate', help='验证 key 命名规范')
    validate_parser.add_argument('--verbose', '-v', action='store_true', help='显示详细信息')
    
    args = parser.parse_args()
    
    if not args.command:
        parser.print_help()
        return
    
    manager = RedisKeyManager(verbose=getattr(args, 'verbose', False))
    
    try:
        if args.command == 'list':
            keys = await manager.list_keys(args.category, args.pattern)
            print(f"找到 {len(keys)} 个 key:")
            for key in keys:
                print(f"  {key}")
        
        elif args.command == 'analyze':
            analysis = await manager.analyze_keys()
            manager.print_analysis_report(analysis)
        
        elif args.command == 'clean':
            results = await manager.clean_keys(
                dry_run=args.dry_run,
                categories=args.categories
            )
            print(f"\n📊 清理结果:")
            print(f"  扫描: {results['scanned']}")
            print(f"  清理: {results['cleaned']}")
            print(f"  错误: {results['errors']}")
        
        elif args.command == 'export':
            success = await manager.export_keys(args.output, args.format)
            if not success:
                sys.exit(1)
        
        elif args.command == 'validate':
            results = await manager.validate_keys()
            print(f"\n✅ 验证结果:")
            print(f"  总计: {results['total_keys']}")
            print(f"  有效: {results['valid_keys']}")
            print(f"  无效: {results['invalid_keys']}")
            
            if results['issues'] and args.verbose:
                print("\n⚠️  问题详情:")
                for issue in results['issues'][:10]:
                    print(f"  {issue['key']}: {issue['reason']}")
                if len(results['issues']) > 10:
                    print(f"  ... 还有 {len(results['issues']) - 10} 个问题")
    
    except KeyboardInterrupt:
        print("\n❌ 操作被用户中断")
        sys.exit(1)
    except Exception as e:
        print(f"\n❌ 操作失败: {e}")
        logger.error(f"Redis key 管理工具执行失败: {e}")
        sys.exit(1)


if __name__ == '__main__':
    asyncio.run(main())
